/*
 * @Author: lineCode 1145938682@qq.com
 * @Date: 2025-08-28 22:42:19
 * @LastEditors: lineCode 1145938682@qq.com
 * @LastEditTime: 2025-11-09 22:01:16
 * @FilePath: /shorthand-go/cmd/migrate/main.go
 */
package main

import (
	"flag"
	"fmt"
	"os"
	"path/filepath"

	"shorthand-go/dao/migration"
	"shorthand-go/dao/resource"

	"go.uber.org/zap"
	"gopkg.in/yaml.v3"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
)

func main() {
	// 定义命令行参数
	var (
		configPath    string
		appMode       string
		command       string
		migrationsDir string
	)

	flag.StringVar(&configPath, "conf", "./conf/app-dev.yml", "配置文件路径")
	flag.StringVar(&appMode, "mode", "dev", "运行模式 (dev/prod)")
	flag.StringVar(&command, "cmd", "migrate", "命令 (migrate/rollback/rollback-all)")
	flag.StringVar(&migrationsDir, "dir", "./dao/migration/sql", "迁移文件目录")
	flag.Parse()

	// 根据运行模式调整配置路径
	if appMode == "prod" {
		configPath = "./conf/app-prod.yml"
		fmt.Println("使用生产环境配置")
	} else {
		fmt.Println("使用开发环境配置")
	}

	// 确保迁移文件目录存在
	if _, err := os.Stat(migrationsDir); os.IsNotExist(err) {
		if err := os.MkdirAll(migrationsDir, 0755); err != nil {
			fmt.Fprintf(os.Stderr, "创建迁移文件目录失败: %v\n", err)
			os.Exit(1)
		}
		fmt.Printf("已创建迁移文件目录: %s\n", migrationsDir)
	}

	// 读取配置文件
	file, err := os.ReadFile(configPath)
	if err != nil {
		fmt.Fprintf(os.Stderr, "读取配置文件失败: %v\n", err)
		os.Exit(1)
	}

	// 解析配置文件
	var config resource.Conf
	if err = yaml.Unmarshal(file, &config); err != nil {
		fmt.Fprintf(os.Stderr, "解析配置文件失败: %v\n", err)
		os.Exit(1)
	}

	// 初始化日志
	logger, err := initLogger(config)
	if err != nil {
		fmt.Fprintf(os.Stderr, "初始化日志失败: %v\n", err)
		os.Exit(1)
	}
	defer logger.Sync()

	// 连接数据库
	db, err := gorm.Open(mysql.Open(config.Mysql.DSN))
	if err != nil {
		logger.Fatal("数据库连接失败", zap.Error(err))
	}

	// 创建迁移管理器
	migrationsDir, err = filepath.Abs(migrationsDir)
	if err != nil {
		logger.Fatal("获取迁移文件目录绝对路径失败", zap.Error(err))
	}

	mgr := migration.NewManager(db, migrationsDir, logger)

	// 执行命令
	switch command {
	case "migrate":
		fmt.Println("开始执行数据库迁移...")
		if err := mgr.Migrate(); err != nil {
			fmt.Fprintf(os.Stderr, "迁移失败: %v\n", err)
			os.Exit(1)
		}
		fmt.Println("数据库迁移完成")

	case "rollback":
		fmt.Println("开始回滚最近一次迁移...")
		if err := mgr.Rollback(); err != nil {
			fmt.Fprintf(os.Stderr, "回滚失败: %v\n", err)
			os.Exit(1)
		}
		fmt.Println("数据库回滚完成")

	case "rollback-all":
		fmt.Println("开始回滚所有迁移...")
		if err := mgr.RollbackAll(); err != nil {
			fmt.Fprintf(os.Stderr, "回滚失败: %v\n", err)
			os.Exit(1)
		}
		fmt.Println("所有数据库迁移已回滚")

	default:
		fmt.Fprintf(os.Stderr, "未知命令: %s\n可用命令: migrate, rollback, rollback-all\n", command)
		os.Exit(1)
	}
}

// initLogger 初始化日志
func initLogger(logConfig resource.Conf) (*zap.Logger, error) {
	config := zap.NewProductionConfig()
	config.OutputPaths = []string{"stdout", logConfig.Log.Filename}
	config.ErrorOutputPaths = []string{"stderr", logConfig.Log.Filename}

	// 设置日志级别
	level, err := zap.ParseAtomicLevel(logConfig.Log.Level)
	if err != nil {
		return nil, fmt.Errorf("解析日志级别失败: %v", err)
	}
	config.Level = level

	// 创建日志目录
	logDir := filepath.Dir(logConfig.Log.Filename)
	if _, err := os.Stat(logDir); os.IsNotExist(err) {
		if err := os.MkdirAll(logDir, 0755); err != nil {
			return nil, fmt.Errorf("创建日志目录失败: %v", err)
		}
	}

	return config.Build()
}
